package com.paziy.jan.fraction;

import java.util.Comparator;

/**
 * Created with IntelliJ IDEA.
 * User: cedrik
 * Date: 18.10.12
 * Time: 9:58
 * To change this template use File | Settings | File Templates.
 */

public class Fraction extends Number implements Cloneable, Comparable, Comparator<Fraction> {
    private int numerator = 0;
    private int denominator = 1;
    private int divider;

    public Fraction() {
        setNumerator(0);
    }

    /**
     * Init only by numerator, denominator = 1
     *
     * @param numerator
     */
    public Fraction(int numerator) {
        setNumerator(numerator);
    }

    public Fraction(int numerator, int denominator) {
        setDenominator(denominator);
        setNumerator(numerator);
        this.reduce();
    }

    public Fraction(Double value) {
        StringBuilder str = new StringBuilder(value.toString());
        boolean repeat = true;

        int point = str.indexOf(".");
        str.deleteCharAt(point);

        while (repeat) {
            try {
                setNumerator(Integer.parseInt(str.toString()));
                repeat = false;
            } catch (Exception e) {
                str.deleteCharAt(str.length() - 1);
            }
        }

        setDenominator((int) java.lang.Math.pow(10, str.length() - point));

        reduce();
    }

    public int getNumerator() {
        return numerator;
    }

    public int getDenominator() {
        return denominator;
    }

    public int getDivider() {
        return divider;
    }

    public final void setNumerator(int numerator) {
        this.numerator = numerator;
        reduce();
    }

    public final void setDenominator(int denominator) {
        if (denominator != 0) {
            if (denominator < 0) {
                this.numerator = - this.numerator;
                this.denominator = - denominator;
            } else {
                this.denominator = denominator;
            }
        } else {
            throw new java.lang.ArithmeticException("division by zero, denominator cant by zero");
        }

        reduce();
    }

    private void reduce() {
        divider = FMath.gcd(numerator, denominator);

        numerator /= divider;
        denominator /= divider;
    }

    /**
     * Applying users operation "o" to this fraction
     *
     * @param o the operation with implements com.paziy.jan.fraction.Operation
     * @return
     */
    public final Object operation(Operation o) {
        return o.apply(this);
    }


    /**
     * **************************************
     * Implements and overrides
     * ***************************************
     */

    public float floatValue() {
        return (float) this.doubleValue();
    }

    public int intValue() {
        return (int) this.doubleValue();
    }

    public long longValue() {
        return (long) this.doubleValue();
    }

    public double doubleValue() {
        return (double) (numerator / denominator);
    }

    @Override
    public String toString() {
        if (denominator == 1 || numerator == 0) {
            return Integer.toString(numerator);
        } else {
            return Integer.toString(numerator) + "/" + Integer.toString(denominator);
        }
    }

    /**
     * Equals fraction
     *
     * @param obj
     * @return
     */
    public boolean equals(Object obj) {
        Fraction a = (Fraction) obj;
        int lc = FMath.lcm(this.denominator, a.denominator);
        return lc / this.denominator * this.numerator == lc / a.denominator * a.numerator;
    }

    @Override
    public Fraction clone() {
        return new Fraction(numerator, denominator);
    }

    public int compareTo(Object obj) {
        return FMath.subtraction(this, (Fraction) obj).numerator;
    }

    /**
     * @param a
     * @param b
     * @return
     */
    public int compare(Fraction a, Fraction b) {
        return a.compareTo(b);
    }

}